"""
API网关 - 统一的API入口
提供路由、认证、限流、监控等功能
"""
import asyncio
import json
import time
import uuid
from typing import Dict, Any, Optional, List, Callable
from datetime import datetime
from dataclasses import dataclass
from loguru import logger

from middleware.redis_adapter import get_redis_adapter
from api_gateway.middleware.jwt_auth import JWTManager, JWTConfig, jwt_required
from api_gateway.middleware.rate_limiter import RateLimiter
from api_gateway.middleware.circuit_breaker import CircuitBreaker
from api_gateway.middleware.request_validator import RequestValidator
from utils.logger import Logger
from utils.exceptions import APIException, ErrorCode


@dataclass
class RouteConfig:
    """路由配置"""
    path: str
    method: str
    target_service: str
    target_path: str
    auth_required: bool = True
    permissions: List[str] = None
    rate_limit: int = 100  # 每分钟请求数
    timeout: int = 30  # 秒
    circuit_breaker_config: Dict = None


@dataclass
class GatewayRequest:
    """网关请求"""
    request_id: str
    method: str
    path: str
    headers: Dict[str, str]
    body: Any
    query_params: Dict[str, str]
    client_ip: str
    timestamp: datetime
    user_id: Optional[str] = None


@dataclass
class GatewayResponse:
    """网关响应"""
    request_id: str
    status_code: int
    headers: Dict[str, str]
    body: Any
    duration_ms: float
    timestamp: datetime


class APIGateway:
    """API网关主类"""
    
    def __init__(self, config: Dict[str, Any] = None):
        self.config = config or {}
        self.logger = Logger.get_logger(agent_name="api_gateway")
        
        # 初始化组件
        self.redis_client = get_redis_adapter()
        self.jwt_manager = JWTManager(self.redis_client)
        self.rate_limiter = RateLimiter(self.redis_client)
        self.circuit_breakers: Dict[str, CircuitBreaker] = {}
        self.request_validator = RequestValidator()
        
        # 路由配置
        self.routes: Dict[str, RouteConfig] = {}
        self.middleware_chain: List[Callable] = []
        
        # 监控指标
        self.request_count = 0
        self.error_count = 0
        self.request_duration_histogram = []
        
        self.logger.info("API网关初始化完成")
    
    def register_route(self, route_config: RouteConfig):
        """注册路由"""
        try:
            route_key = f"{route_config.method}:{route_config.path}"
            self.routes[route_key] = route_config
            
            # 为每个服务创建熔断器
            if route_config.target_service not in self.circuit_breakers:
                cb_config = route_config.circuit_breaker_config or {
                    "failure_threshold": 5,
                    "recovery_timeout": 60,
                    "expected_exception": Exception
                }
                self.circuit_breakers[route_config.target_service] = CircuitBreaker(
                    **cb_config
                )
            
            self.logger.info(f"路由注册成功: {route_key} -> {route_config.target_service}")
            
        except Exception as e:
            self.logger.error(f"路由注册失败: {str(e)}")
            raise
    
    def add_middleware(self, middleware: Callable):
        """添加中间件"""
        self.middleware_chain.append(middleware)
        self.logger.info(f"中间件添加成功: {middleware.__name__}")
    
    async def handle_request(self, request: GatewayRequest) -> GatewayResponse:
        """处理请求"""
        start_time = time.time()
        request_id = str(uuid.uuid4())
        
        try:
            self.logger.info(f"处理请求: {request.method} {request.path}, ID: {request_id}")
            
            # 查找路由
            route_key = f"{request.method}:{request.path}"
            route_config = self.routes.get(route_key)
            
            if not route_config:
                raise APIException(
                    error_code=ErrorCode.ROUTE_NOT_FOUND,
                    message=f"路由未找到: {request.method} {request.path}"
                )
            
            # 执行中间件链
            current_request = request
            for middleware in self.middleware_chain:
                current_request = await middleware(current_request, route_config)
            
            # 认证检查
            if route_config.auth_required:
                current_request = await self._authenticate_request(current_request, route_config)
            
            # 限流检查
            await self._check_rate_limit(current_request, route_config)
            
            # 请求验证
            await self._validate_request(current_request, route_config)
            
            # 调用目标服务
            response = await self._call_target_service(current_request, route_config)
            
            # 记录成功指标
            duration_ms = (time.time() - start_time) * 1000
            self._record_metrics(request_id, True, duration_ms)
            
            self.logger.info(f"请求处理成功: ID={request_id}, 耗时={duration_ms:.2f}ms")
            
            return GatewayResponse(
                request_id=request_id,
                status_code=response.get("status_code", 200),
                headers=response.get("headers", {}),
                body=response.get("body", {}),
                duration_ms=duration_ms,
                timestamp=datetime.utcnow()
            )
            
        except APIException as e:
            # 记录API异常
            duration_ms = (time.time() - start_time) * 1000
            self._record_metrics(request_id, False, duration_ms)
            
            self.logger.warning(f"API异常: ID={request_id}, 错误={e.message}")
            
            return GatewayResponse(
                request_id=request_id,
                status_code=e.error_code.http_status,
                headers={"Content-Type": "application/json"},
                body={
                    "error_code": e.error_code.code,
                    "message": e.message,
                    "request_id": request_id,
                    "timestamp": datetime.utcnow().isoformat()
                },
                duration_ms=duration_ms,
                timestamp=datetime.utcnow()
            )
            
        except Exception as e:
            # 记录系统异常
            duration_ms = (time.time() - start_time) * 1000
            self._record_metrics(request_id, False, duration_ms)
            self.error_count += 1
            
            self.logger.error(f"系统异常: ID={request_id}, 错误={str(e)}")
            
            return GatewayResponse(
                request_id=request_id,
                status_code=500,
                headers={"Content-Type": "application/json"},
                body={
                    "error_code": "INTERNAL_ERROR",
                    "message": "内部服务器错误",
                    "request_id": request_id,
                    "timestamp": datetime.utcnow().isoformat()
                },
                duration_ms=duration_ms,
                timestamp=datetime.utcnow()
            )
    
    async def _authenticate_request(self, request: GatewayRequest, 
                                  route_config: RouteConfig) -> GatewayRequest:
        """认证请求"""
        try:
            # 从请求头获取令牌
            auth_header = request.headers.get("Authorization", "")
            if not auth_header.startswith("Bearer "):
                raise APIException(
                    error_code=ErrorCode.UNAUTHORIZED,
                    message="缺少有效的认证令牌"
                )
            
            token = auth_header.replace("Bearer ", "")
            
            # 验证令牌
            payload = self.jwt_manager.verify_token(token)
            if not payload:
                raise APIException(
                    error_code=ErrorCode.UNAUTHORIZED,
                    message="无效或过期的令牌"
                )
            
            # 检查权限
            if route_config.permissions:
                user_permissions = payload.get("permissions", [])
                if not any(perm in user_permissions for perm in route_config.permissions):
                    raise APIException(
                        error_code=ErrorCode.FORBIDDEN,
                        message="权限不足"
                    )
            
            # 添加用户信息到请求
            request.user_id = payload["user_id"]
            request.headers["X-User-ID"] = payload["user_id"]
            request.headers["X-User-Name"] = payload["username"]
            
            self.logger.debug(f"认证成功: user={payload['username']}, path={request.path}")
            
            return request
            
        except APIException:
            raise
        except Exception as e:
            self.logger.error(f"认证失败: {str(e)}")
            raise APIException(
                error_code=ErrorCode.UNAUTHORIZED,
                message="认证失败"
            )
    
    async def _check_rate_limit(self, request: GatewayRequest, 
                               route_config: RouteConfig):
        """检查限流"""
        try:
            client_id = request.client_ip
            if request.user_id:
                client_id = request.user_id
            
            allowed = await self.rate_limiter.is_allowed(
                client_id=client_id,
                limit=route_config.rate_limit,
                window_seconds=60  # 1分钟窗口
            )
            
            if not allowed:
                raise APIException(
                    error_code=ErrorCode.RATE_LIMIT_EXCEEDED,
                    message="请求过于频繁，请稍后再试"
                )
                
        except APIException:
            raise
        except Exception as e:
            self.logger.error(f"限流检查失败: {str(e)}")
            # 限流检查失败时，允许请求通过（fail-open）
    
    async def _validate_request(self, request: GatewayRequest, 
                              route_config: RouteConfig):
        """验证请求"""
        try:
            # 基础验证
            if not request.method or not request.path:
                raise APIException(
                    error_code=ErrorCode.INVALID_REQUEST,
                    message="请求格式无效"
                )
            
            # 请求体大小检查
            if request.body:
                body_size = len(json.dumps(request.body))
                if body_size > 10 * 1024 * 1024:  # 10MB限制
                    raise APIException(
                        error_code=ErrorCode.REQUEST_TOO_LARGE,
                        message="请求体过大"
                    )
            
            # 自定义验证规则
            await self.request_validator.validate(request, route_config)
            
        except APIException:
            raise
        except Exception as e:
            self.logger.error(f"请求验证失败: {str(e)}")
            raise APIException(
                error_code=ErrorCode.INVALID_REQUEST,
                message="请求验证失败"
            )
    
    async def _call_target_service(self, request: GatewayRequest, 
                                 route_config: RouteConfig) -> Dict[str, Any]:
        """调用目标服务"""
        try:
            # 获取熔断器
            circuit_breaker = self.circuit_breakers.get(route_config.target_service)
            if not circuit_breaker:
                # 如果没有熔断器，直接调用
                return await self._direct_call(request, route_config)
            
            # 通过熔断器调用
            return await circuit_breaker.call(
                self._direct_call, request, route_config
            )
            
        except APIException:
            raise
        except Exception as e:
            self.logger.error(f"调用目标服务失败: {str(e)}")
            raise APIException(
                error_code=ErrorCode.SERVICE_UNAVAILABLE,
                message="目标服务不可用"
            )
    
    async def _direct_call(self, request: GatewayRequest, 
                          route_config: RouteConfig) -> Dict[str, Any]:
        """直接调用目标服务"""
        try:
            # 这里应该实现实际的服务调用逻辑
            # 目前返回模拟响应
            return {
                "status_code": 200,
                "headers": {"Content-Type": "application/json"},
                "body": {
                    "message": f"调用 {route_config.target_service} 成功",
                    "path": route_config.target_path,
                    "request_id": request.request_id
                }
            }
            
        except Exception as e:
            self.logger.error(f"直接调用失败: {str(e)}")
            raise
    
    def _record_metrics(self, request_id: str, success: bool, duration_ms: float):
        """记录监控指标"""
        self.request_count += 1
        self.request_duration_histogram.append(duration_ms)
        
        # 保持直方图大小
        if len(self.request_duration_histogram) > 1000:
            self.request_duration_histogram = self.request_duration_histogram[-1000:]
        
        if not success:
            self.error_count += 1
    
    def get_metrics(self) -> Dict[str, Any]:
        """获取监控指标"""
        if not self.request_duration_histogram:
            return {
                "total_requests": self.request_count,
                "error_count": self.error_count,
                "error_rate": 0.0,
                "avg_duration_ms": 0.0,
                "p95_duration_ms": 0.0,
                "p99_duration_ms": 0.0
            }
        
        sorted_durations = sorted(self.request_duration_histogram)
        error_rate = self.error_count / max(self.request_count, 1)
        
        return {
            "total_requests": self.request_count,
            "error_count": self.error_count,
            "error_rate": error_rate,
            "avg_duration_ms": sum(sorted_durations) / len(sorted_durations),
            "p95_duration_ms": sorted_durations[int(len(sorted_durations) * 0.95)],
            "p99_duration_ms": sorted_durations[int(len(sorted_durations) * 0.99)]
        }


# 创建网关实例的工厂函数
def create_api_gateway(config: Dict[str, Any] = None) -> APIGateway:
    """创建API网关实例"""
    gateway = APIGateway(config)
    
    # 注册默认路由
    default_routes = [
        RouteConfig(
            path="/api/v1/documents",
            method="GET",
            target_service="document_service",
            target_path="/documents",
            auth_required=True,
            permissions=["documents:read"],
            rate_limit=100
        ),
        RouteConfig(
            path="/api/v1/documents",
            method="POST",
            target_service="document_service",
            target_path="/documents",
            auth_required=True,
            permissions=["documents:write"],
            rate_limit=50
        ),
        RouteConfig(
            path="/api/v1/search",
            method="GET",
            target_service="search_service",
            target_path="/search",
            auth_required=True,
            permissions=["search:read"],
            rate_limit=200
        ),
        RouteConfig(
            path="/api/v1/search",
            method="POST",
            target_service="search_service",
            target_path="/search",
            auth_required=True,
            permissions=["search:read"],
            rate_limit=200
        ),
        RouteConfig(
            path="/api/v1/auth/login",
            method="POST",
            target_service="auth_service",
            target_path="/login",
            auth_required=False,
            rate_limit=10
        ),
        RouteConfig(
            path="/api/v1/auth/refresh",
            method="POST",
            target_service="auth_service",
            target_path="/refresh",
            auth_required=False,
            rate_limit=10
        )
    ]
    
    for route in default_routes:
        gateway.register_route(route)
    
    return gateway